from CvPythonExtensions import *

import GerikSpells
from GerikSpells import GerikSpellBase
from GSGroupPolicies import GSAll as GSGroup
from GSHandlerPolicies import GSTargetting as GSHandler
from GSResultsPolicies import GSMission as GSResults
from GSHandlerPolicies import GSImmediateNoTarget as GSImmediateNoTargetHandler
from GSResultsPolicies import GSMissionNoTarget as GSMissionNoTargetResults


from GSTargetInfoPolicies import GSSinglePlotTarget
from CivcraftPolicies import CivcraftSpecificUnitTargetPolicy as GSSpecificUnitTarget

from CivcraftPolicies import CivcraftSpellPlotGraphicsPolicy as GSPlot
from GSGraphicsPolicies import GSPieMenu

import GerikSpellsUtils

from CivcraftSCUtils import checkAndRemoveEnergy
from CivcraftSCUtils import showNotEnoughEnergyMsg
from CivcraftSCUtils import getEnergyUsageString
from CivcraftSCUtils import isHallucination

gc = CyGlobalContext()
localtext = CyTranslator()

class GhostBase(GerikSpellBase, GSGroup, GSHandler):
    def __init__(self):
        GerikSpellBase.__init__(self)
        GSGroup.__init__(self)
        GSHandler.__init__(self)


        self.m_iGhostType = gc.getInfoTypeForString("UNIT_GHOST")
            
    def canUnitCast(self, pCastingUnit, pPlot, bVisible):
        if not pCastingUnit.getUnitType() == self.m_iGhostType:
            return False

        if isHallucination(pCastingUnit):
            return False

        # Show this for all ghosts.
        if bVisible:
            return True

        return True

class Lockdown(GhostBase, GSResults):
    def __init__(self):
        GhostBase.__init__(self)

        # Constants
        self.m_iLockdownEnergyCost = 75
        self.m_iLockdownRange = 5
        self.m_iLockdownUnitAttachment = gc.getInfoTypeForString("UNIT_ATTACHMENT_LOCKDOWN")

        self.m_iResearchNeeded = gc.getInfoTypeForString("PROJECT_TERRAN_GHOST_LOCKDOWN")
        self.m_iResearchBuildingToBuildAt = gc.getProjectInfo(self.m_iResearchNeeded).getBuildingToBuildAt()
        self.m_szNotValidText = localtext.getText( "TXT_KEY_CIVCRAFT_REQUIRES_RESEARCH_AT", (gc.getProjectInfo(self.m_iResearchNeeded).getDescription(),
                                                                                             gc.getBuildingInfo(self.m_iResearchBuildingToBuildAt).getDescription()) )

        # Policies
        pSpecificUnitTargetPolicy = GSSpecificUnitTarget(self.canTargetUnit)
        GSResults.__init__(self, pSpecificUnitTargetPolicy)

    def getHelpText(self, pGroup, pPlot):
        szText = getEnergyUsageString(self.m_iLockdownEnergyCost)

        bValid = self.canGroupCast(pGroup, pPlot, False)
        if not bValid:
            szText += self.m_szNotValidText
        else:
            szText += gc.getSpellInfo(self.getSpellNumber()).getHelp()

        return szText

    def canUnitCast(self, pCastingUnit, pPlot, bVisible):
        if not GhostBase.canUnitCast(self, pCastingUnit, pPlot, bVisible):
            return False

        if bVisible:
            return True

        # Check if they have the research
        if not gc.getPlayer( pCastingUnit.getOwner() ).hasBuiltProject( self.m_iResearchNeeded ):
            return False

        return True

    def canTargetPlot(self, pCastingGroup, pCastingPlot, pTargetPlot, bVisible):
        return True

    def canTargetUnit(self, pCastingGroup, pCastingPlot, pTargetUnit, bVisible):
        if bVisible:
            return True

        # Check for invulnerable units
        if pTargetUnit.isInvulnerable():
            return False

        # Only be able to cast on mechanical units.
        if not gc.getUnitInfo(pTargetUnit.getUnitType()).isMechanical():
            return False

        return True

    def getRangePlotList(self, pCastingPlot):
        return GerikSpellsUtils.getRangePlotDistanceList(pCastingPlot, self.m_iLockdownRange)

    def createTargettingStageList(self, bAlt, bShift, bCtrl):
        pStageList = []

        pPlotTargetPolicy = GSSinglePlotTarget(self.canTargetPlot)
        pPlotTargetPolicy.setRangeMakerCallback(self.getRangePlotList)
        pPlotTargetPolicy.setCheckRange(True)

        pPlotGraphicsPolicy = GSPlot()
        pPlotGraphicsPolicy.setShowRangeGraphics(True)
        pPlotGraphicsPolicy.setCursorType("CURSOR_SINGLE_ATTACK")
        
        pStageList.append( (pPlotTargetPolicy, pPlotGraphicsPolicy) )

        pUnitTargetPolicy = GSSpecificUnitTarget(self.canTargetUnit)
        pUnitTargetPolicy.setInvalidTargetDescriptionCallback(self.getInvalidTargetText)
        pUnitMenuPolicy = GSPieMenu()
        pStageList.append( (pUnitTargetPolicy, pUnitMenuPolicy) )

        return pStageList

    def getInvalidTargetText(self, pTargetUnit, bStrategyText):
        szText = u""
        pCastingGroup = self.getCastingGroup()
        if pCastingGroup.getOwner() == pTargetUnit.getOwner():
            szText += u"\n"
            szText += localtext.getText("TXT_KEY_INVALID_TARGET_SAME_TEAM", ())

        if pTargetUnit.isInvulnerable():
            szText += u"\n"
            szText += localtext.getText("TXT_KEY_INVALID_TARGET_UNIT_INULNERABLE", ())

        if not gc.getUnitInfo(pTargetUnit.getUnitType()).isMechanical():
            szText += u"\n"
            szText += localtext.getText("TXT_KEY_INVALID_TARGET_NON_MECHANICAL", ())

        return szText

    def startSpellResults(self, pCastingGroup, pTargetInfo):
        bShowNotEnoughEnergy = False
        
        iPlayer = pCastingGroup.getOwner()
        for pUnit in pCastingGroup.getUnits():
            if checkAndRemoveEnergy(pUnit, self.m_iLockdownEnergyCost):
                print pTargetInfo.getTarget()
                for pLoopUnit in pTargetInfo.getAffectedTargetList(pCastingGroup, pCastingGroup.plot()):
                    
                    pLoopUnit.attachUnitAttachment(iPlayer, self.m_iLockdownUnitAttachment)
            else:
                bShowNotEnoughEnergy = True

        if bShowNotEnoughEnergy:
            showNotEnoughEnergyMsg(iPlayer)
            

class Nuke(GhostBase, GSResults):
    def __init__(self):
        GhostBase.__init__(self)

        # Constants
        self.m_iNukeType = gc.getInfoTypeForString("UNIT_NUKE")

        self.m_iUnitBuildingToBuildAt = gc.getUnitInfo(self.m_iNukeType).getBuildingToBuildAt()
        self.m_szNotValidText = localtext.getText( "TXT_KEY_CIVCRAFT_REQUIRES_UNIT_BUILT_AT", (gc.getUnitInfo(self.m_iNukeType).getDescription(),
                                                                                               gc.getBuildingInfo(self.m_iUnitBuildingToBuildAt).getDescription()) )

        # Policies
        pPlotTargetPolicy = GSSinglePlotTarget(self.canTargetPlot)
        GSResults.__init__(self, pPlotTargetPolicy)

    def getHelpText(self, pGroup, pPlot):
        szText = ""
        bValid = self.canGroupCast(pGroup, pPlot, False)
        if not bValid:
            szText += self.m_szNotValidText
        else:
            szText += gc.getSpellInfo(self.getSpellNumber()).getHelp()

        return szText

    def canUnitCast(self, pCastingUnit, pPlot, bVisible):
        if not GhostBase.canUnitCast(self, pCastingUnit, pPlot, bVisible):
            return False

        # Can't nuke if already nuking
        if pCastingUnit.hasNukeTargetPlot():
            return False

        if bVisible:
            return True

        # Check if they have the research
        if not gc.getPlayer( pCastingUnit.getOwner() ).hasTrainedUnitAtAddon(self.m_iNukeType):
            return False

        return True

    def canTargetPlot(self, pCastingGroup, pCastingPlot, pTargetPlot, bVisible):
        return True

    def getRangePlotList(self, pCastingPlot):
        iVisibility = 0
        for pUnit in self.getCastingGroup().getUnits():
            if self.canUnitCast(pUnit, pCastingPlot, False):
                iVisibility = pUnit.visibilityRange()
                                  
        return GerikSpellsUtils.getRangePlotDistanceList(pCastingPlot, iVisibility - 1)

    def createTargettingStageList(self, bAlt, bShift, bCtrl):
        pStageList = []

        pPlotTargetPolicy = GSSinglePlotTarget(self.canTargetPlot)
        pPlotTargetPolicy.setRangeMakerCallback(self.getRangePlotList)
        pPlotTargetPolicy.setCheckRange(True)

        pPlotGraphicsPolicy = GSPlot()
        pPlotGraphicsPolicy.setShowRangeGraphics(True)
        pPlotGraphicsPolicy.setCursorType("CURSOR_SINGLE_ATTACK")
        
        pStageList.append( (pPlotTargetPolicy, pPlotGraphicsPolicy) )

        return pStageList

    def startSpellResults(self, pCastingGroup, pTargetInfo):
        bShowNotEnoughEnergy = False
        
        iPlayer = pCastingGroup.getOwner()
        pPlayer = gc.getPlayer(iPlayer)
        for pUnit in pCastingGroup.getUnits():
            for pTargetPlot in pTargetInfo.getAffectedTargetList(pCastingGroup, pCastingGroup.plot()):
                if self.canUnitCast(pUnit, pTargetPlot, False):
                    pUnit.setNukeTargetPlot( pTargetPlot.getX(), pTargetPlot.getY() )
                    pPlayer.removeTrainedUnitAtAddon(self.m_iNukeType);

                    

                        
class CancelNuke(GerikSpellBase, GSGroup, GSImmediateNoTargetHandler, GSMissionNoTargetResults):
    def __init__(self):
        GerikSpellBase.__init__(self)
        GSGroup.__init__(self)
        GSImmediateNoTargetHandler.__init__(self)
        GSMissionNoTargetResults.__init__(self)


        self.m_iGhostType = gc.getInfoTypeForString("UNIT_GHOST")
            
    def canUnitCast(self, pCastingUnit, pPlot, bVisible):
        if not pCastingUnit.getUnitType() == self.m_iGhostType:
            return False

        if isHallucination(pCastingUnit):
            return False

        # Show this for all ghosts.
        if bVisible:
            return True

        return True

        # Policies
        pPlotTargetPolicy = GSSinglePlotTarget(self.canTargetPlot)
        GSResults.__init__(self, pPlotTargetPolicy)

    def canUnitCast(self, pCastingUnit, pPlot, bVisible):
        if not pCastingUnit.getUnitType() == self.m_iGhostType:
            return False

        if isHallucination(pCastingUnit):
            return False

        # Can't cancel nuke if not nuking
        if not pCastingUnit.hasNukeTargetPlot():
            return False

        if bVisible:
            return True

        return True


    def startSpellResults(self, pCastingGroup, pTargetInfo):
        bShowNotEnoughEnergy = False
        
        iPlayer = pCastingGroup.getOwner()
        pPlayer = gc.getPlayer(iPlayer)
        for pUnit in pCastingGroup.getUnits():
            pUnit.clearNukeTargetPlot()

                        
        
        
            
            
